package svc.elib.socnet;

import java.io.IOException;
import java.util.Iterator;
import java.util.LinkedList;

import svc.elib.db.Author;
import svc.elib.db.Database;
import svc.elib.db.Paper;

/**
 * Determines trivial (one paper) components
 * 
 * @author svc
 * @date 8.6.2013
 */
public class TrivialComponents {

	private Net net;
	
	/**
	 * This set contains trivial components 
	 */
	private LinkedList<Net> trivial = new LinkedList<Net>();
	
	// number of components
	private int numComponents;
	
	// number of trivial components;
	private int numTrivial;
	
	// number of one paper components;
	private int numOnePaperComponents;
	
	// number of authors in trivial components
	private int numAuthorsInTrivialComponents;
	
	public TrivialComponents(Net net) {
		this.net = net;
		//determine();
	}
	
	/**
	 * Determines all trivial components
	 */
	public void determine() {
		ConnectedComponents comp = new ConnectedComponents(net);
		comp.resolveComponents();
		
		numTrivial = 0;
		numOnePaperComponents = 0;
		numAuthorsInTrivialComponents = 0;
		
		LinkedList<Net> components =  comp.getComponents();
		numComponents = components.size();
		for (int i = 0; i < components.size(); i++) {
			Net component = components.get(i);
			if (isTrivial2(component)) {
				trivial.add(component);
				++numTrivial;
				numAuthorsInTrivialComponents += component.getNumAuthors();
			}
		}
	}

	/**
	 * Checks if component is trivial. Component is trivial if for each author 
	 * the number of non collaborative papers is equal to the total number of 
	 * papers minus one
	 * 
	 * @param component
	 * @return
	 */
	public boolean isTrivial(Net component) {
		Iterator<Author> ait = component.getGraph().getVertices().iterator();
		boolean strictlyOnePaperComponent = true;
		boolean trivial = true;
		
		int numAuthorsInComponent = component.getGraph().getVertices().size();
		if (numAuthorsInComponent == 1)
			return true;
		
		while (ait.hasNext()) {
			Author a = ait.next();
			LinkedList<Paper> aPapers = a.getPapers();
			int numCollaborativePapers = 0;
			for (int i = 0; i < aPapers.size(); i++) {
				Paper p = aPapers.get(i);
				if (p.getAuthors().size() > 1)
					numCollaborativePapers++;
			}
			
			if (aPapers.size() > numAuthorsInComponent)
				strictlyOnePaperComponent = false;
			
			if (numCollaborativePapers > 1)
				trivial = false;
		}
		
		if (trivial && strictlyOnePaperComponent) {
			++numOnePaperComponents;
		}
		
		return trivial;
	}
	
	public boolean isTrivial2(Net component) {
		Iterator<Author> ait = component.getGraph().getVertices().iterator();
		int numAuthorsInComponent = component.getGraph().getVertices().size();
		if (numAuthorsInComponent == 1) {
			System.out.println("TrivialComponents.isTrivial2 -- this never happens");
			return true;
		}
		
		while (ait.hasNext()) {
			Author a = ait.next();
			LinkedList<Paper> aPapers = a.getPapers();
			int numCollaborativePapers = 0;
			for (int i = 0; i < aPapers.size(); i++) {
				Paper p = aPapers.get(i);
				if (p.getAuthors().size() > 1)
					numCollaborativePapers++;
			}
			
			if (numCollaborativePapers > 1) {
				return false;
			}
		}
		
		return true;
	}

	/**
	 * removes trivial components (and isolated nodes)
	 */
	public void filter() {
		for (int i = 0; i < trivial.size(); i++) {
			Net t = trivial.get(i);
			Iterator<Author> it = t.getGraph().getVertices().iterator();
			while (it.hasNext()) {
				Author a = it.next();
				net.getGraph().removeVertex(a);
			}
		}
		
		LinkedList<Author> isolated = new LinkedList<Author>();
		Iterator<Author> it = net.getGraph().getVertices().iterator();
		while (it.hasNext()) {
			Author a = it.next();
			if (net.getGraph().degree(a) == 0)
				isolated.add(a);
		}
		
		for (int i = 0; i < isolated.size(); i++) {
			net.getGraph().removeVertex(isolated.get(i));
		}
	}
	
	public void info() {
		System.out.println("\nTrivial components report ------------ ");
		System.out.println("Number of components: " + numComponents);
		System.out.println("Number of trivial components: " + numTrivial);
		System.out.println("Number of one paper components: " + numOnePaperComponents);
		System.out.println("Number of authors in trivial components: " + numAuthorsInTrivialComponents);
	}
	
	public int getNumAuthorsInTrivialComponents() {
		return numAuthorsInTrivialComponents;
	}
	
	public int getNumTrivial() {
		return numTrivial;
	}
	
	public static void main(String[] args) 
		throws IOException
	{
		Database db = new Database("eLibData.csv", 1932, 2011);
		System.out.println(db.info());
		SocConstructor soc = new SocConstructor(db);
		Net net = soc.getNet();
		net.printInfo();
		
		TrivialComponents tc = new TrivialComponents(net);
		tc.determine();
		tc.info();
		
		System.out.println("\nRemoving trivial components");
		tc.filter();
		net.printInfo();
		
		ConnectedComponents comp = new ConnectedComponents(net);
		comp.resolveComponents();
		comp.componentsInfo();
	}
	
}
